package com.bearingnavi.android.views;

import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.bearingnavi.android.listeners.RotationGestureListener;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;

public class LongpressMapView extends MapView {
	
	private boolean longpressHandled = false;
	private RotationGestureListener rotationGestureListener = new RotationGestureListener();

	// Define the interface we will interact with from our Map
	public interface OnLongpressListener {
		public void onLongpress(MapView mapView, GeoPoint geoPoint, Point point);
		public void onLongpressStart();
		public void onLongpressEnd();
	}

	/**
	 * Time in ms before the OnLongpressListener is triggered.
	 */
	static final int LONGPRESS_THRESHOLD = 300;

	/**
	 * Keep a record of the center of the map, to know if the map has been
	 * panned.
	 */
	private GeoPoint lastMapCenter;

	private Timer longpressTimer = new Timer();
	private LongpressMapView.OnLongpressListener longpressListener;

	public LongpressMapView(Context context, String apiKey) {
		super(context, apiKey);
	}

	public LongpressMapView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public LongpressMapView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public void setOnLongpressListener(
			LongpressMapView.OnLongpressListener listener) {
		longpressListener = listener;
	}
	
	public boolean isLongpressHandled() {
		return longpressHandled;
	}

	/**
	 * This method is called every time user touches the map, drags a finger on
	 * the map, or removes finger from the map.
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		boolean b = super.onTouchEvent(event);
		handleLongpress(event);
		if (isClickable()) {
			rotationGestureListener.onTouchEvent(event);	
		}

		return b;
	}

	/**
	 * This method takes MotionEvents and decides whether or not a longpress has
	 * been detected. This is the meat of the OnLongpressListener.
	 * 
	 * The Timer class executes a TimerTask after a given time, and we start the
	 * timer when a finger touches the screen.
	 * 
	 * We then listen for map movements or the finger being removed from the
	 * screen. If any of these events occur before the TimerTask is executed, it
	 * gets cancelled. Else the listener is fired.
	 * 
	 * @param event
	 */
	private void handleLongpress(MotionEvent event) {
		
		int x = (int) event.getX();
		int y = (int) event.getY();
		final Point point = new Point(x, y);
		final GeoPoint geoPoint = getProjection().fromPixels(x, y);

		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			// Finger has touched screen.
			longpressListener.onLongpressStart();
			longpressTimer = new Timer();
			longpressTimer.schedule(new TimerTask() {
				@Override
				public void run() {
					/*
					 * Fire the listener. We pass the map location of the
					 * longpress as well, in case it is needed by the caller.
					 */
					longpressHandled = true;
					longpressListener.onLongpress(LongpressMapView.this,
							geoPoint, point);
				}

			}, LONGPRESS_THRESHOLD);

			lastMapCenter = getMapCenter();
		}

		if (event.getAction() == MotionEvent.ACTION_MOVE) {

			if (!getMapCenter().equals(lastMapCenter)) {
				// User is panning the map, this is no longpress
				longpressTimer.cancel();
				longpressListener.onLongpressEnd();
				longpressHandled = false;
			}

			lastMapCenter = getMapCenter();
		}

		if (event.getAction() == MotionEvent.ACTION_UP) {
			// User has removed finger from map.
			longpressTimer.cancel();
			longpressListener.onLongpressEnd();
			longpressHandled = false;
		}

		if (event.getPointerCount() > 1) {
			// This is a multitouch event, probably zooming.
			longpressTimer.cancel();
			longpressListener.onLongpressEnd();
			longpressHandled = false;
		}
	}
}
